package com.kehutong.flow.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.coraframework.authz.HasPermission;
import org.coraframework.inject.Inject;
import org.coraframework.json.JSONArray;
import org.coraframework.json.JSONObject;
import org.coraframework.logger.Logger;
import org.coraframework.logger.LoggerFactory;
import org.coraframework.mvc.http.ReqMapping;
import org.coraframework.mvc.http.result.Result;
import org.coraframework.mvc.webservice.WebService;
import org.coraframework.orm.Pool;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.Page;
import org.coraframework.util.EnumUtil;
import org.coraframework.util.Objects;
import org.coraframework.util.Pair;

import com.kehutong.common.DoveClient;
import com.kehutong.common.util.Token;
import com.kehutong.flow.admin.FlowRuleController;
import com.kehutong.flow.entity.FlowRule;
import com.kehutong.flow.entity.FlowRuleNode;
import com.kehutong.flow.enums.FlowAction;
import com.kehutong.flow.enums.OperationType;
import com.kehutong.flow.enums.Target;
import com.kehutong.flow.enums.TimeUnit;

@WebService("/flow/service/rule")
public class FlowRuleService {

    private static final Logger logger = LoggerFactory.getLogger(FlowRuleController.class);

    @Inject
    private JdbcSession jdbcSession;

    @Inject
    private DoveClient doveClient;

    @ReqMapping("/list")
    public Page<FlowRule> list(JSONObject jsonObject) {
       Page<FlowRule> page = jdbcSession.findPage(FlowRule.class)
                .eq(jsonObject, "id", "type")
                .like(jsonObject,"name")
                .eq("deleted", false)
                .order("createTime", "desc")
                .page(jsonObject)
                .exe();

        page.getList().forEach(flowRule -> {
            flowRule.setUpdateByTime(flowRule.getUpdateTime());
        });

        return page;
    }

    @ReqMapping("/get")
    public Object get(Token token, String id) {
        final FlowRule role = Pool.get(FlowRule.class, id);

        List<FlowRuleNode> nodeList = new ArrayList<>();
        if (Objects.nonNull(role)) {
            role.getNodeList().forEach(nodeNo->{
                FlowRuleNode flowRuleNode = Pool.get(FlowRuleNode.class, nodeNo);
                List<String> departmentNos = flowRuleNode.getDepartmentNos();
                if (departmentNos != null && departmentNos.size() != 0) {

                    JSONObject object = null;
                    try {
                        object = doveClient.post("/basic/department/service/list", (http) -> {
                            http.addHeader("companyNo", token.getCompanyNo());
                            JSONObject jsonObject = new JSONObject();
                            jsonObject.put("id", departmentNos);
                            http.setBody(jsonObject.toString());
                        });
                    } catch (Exception e) {
                        e.printStackTrace();
                        logger.error("获取部门报错：{}", e);
                    }

                    if (object.getInteger("code") == 200) {
                        JSONArray jsonArray = object.getJSONArray("data");
                        List<String> departmentName = new ArrayList<>();
                        jsonArray.forEach(obj -> {
                            JSONObject jsonObject = (JSONObject) obj;
                            departmentName.add(jsonObject.getString("name"));
                        });

                        flowRuleNode.setDepartments(jsonArray);
                        flowRuleNode.setDepartmentName(departmentName);

                    } else {
                        logger.error("获取部门报错{}", object.getString("message"));
                    }
                }
                nodeList.add(flowRuleNode);
            });
        }
        role.setNodes(nodeList);
        return role;
    }

//    @Bean(newInstance=true, copy=true)
    @ReqMapping("/save")
    public Object save(Token token, JSONObject jsonObject) {
        FlowRule flowRule = Pool.newInstance(FlowRule.class);
        flowRule.setName(jsonObject.getString("name"));
        flowRule.setType(jsonObject.getInteger("type"));
        flowRule.setUpdateById(token.getUuid());
        flowRule.setUpdateByName(token.getUsername());

        String[] split = flowRule.getName().split("/");
        if(split.length == 1){
            FlowRule exe = jdbcSession.findOne(FlowRule.class)
                    .eq("type", flowRule.getType())
                    .eq("name", flowRule.getName())
                    .eq("deleted", false).exe();
            if(Objects.nonNull(exe)){
                return Result.error(400, "该业务的规则已存在，请先删除！");
            }
        }

        if(split.length == 2){
            List<FlowRule> exe = jdbcSession.findArray(FlowRule.class)
                    .eq("type", flowRule.getType())
                    .eq("deleted", false).exe();
            if(exe.size() !=0){
                return Result.error(400, "该业务的规则已存在，请先删除！");
            }
        }

        if (addNodes(flowRule, jsonObject.getJSONArray("nodes"))) {
            return Result.error(400, "请选择提醒对象！");
        }

        Pair<List<String>, List<String>> pair = toList(jsonObject);
        flowRule.setKeyids(pair.getKey());
        flowRule.setKeyWords(pair.getValue());
        jdbcSession.insert(flowRule);

        return Result.success();
    }

//    @Bean(copy=true)
    @ReqMapping("/update")
    public Object update(Token token, JSONObject jsonObject) {
        FlowRule item = Pool.get(FlowRule.class, jsonObject.getString("id"));
        item.setName(jsonObject.getString("name"));
        item.setType(jsonObject.getInteger("type"));
        item.setUpdateById(token.getUuid());
        item.setUpdateByName(token.getUsername());

        if (updateNodes(item, jsonObject.getJSONArray("nodes"))) {
            return Result.error(400, "请选择提醒对象和数据源！");
        }

        Pair<List<String>, List<String>> pair = toList(jsonObject);
        item.setKeyids(pair.getKey());
        item.setKeyWords(pair.getValue());
        jdbcSession.updateById(item);
        return Result.success();
    }

    @HasPermission("flow:rule:edit")
    @ReqMapping("/delete")
    public Object delete(String id) {
        final FlowRule role = Pool.get(FlowRule.class, id);
        if (Objects.nonNull(role)) {
            role.setDeleted(true);
            jdbcSession.updateById(role);
        }

        return Result.success();
    }

    @ReqMapping("/enums")
    public JSONObject loadEnums() {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("actions", Arrays.asList(FlowAction.values()));
        jsonObject.put("targets", Arrays.asList(Target.values()));
        jsonObject.put("units", Arrays.asList(TimeUnit.values()));
        jsonObject.put("operation", Arrays.asList(OperationType.values()));

        return jsonObject;
    }

    @ReqMapping("/list/all")
    public Object listAll(JSONObject jsonObject) {
        List<FlowRule> flowRules = jdbcSession.findArray(FlowRule.class)
                .eq(jsonObject, "id", "type")
                .like(jsonObject, "name")
                .eq("deleted", false)
                .order("createTime", "desc")
                .exe();

        flowRules.forEach(flowRule -> {
            flowRule.setUpdateByTime(flowRule.getUpdateTime());
        });

        return flowRules;
    }

    @ReqMapping("/get/flowRuleNode")
    public Object getFlowRuleNode(String id) {
        return Pool.get(FlowRuleNode.class, id);
    }

    private boolean addNodes(FlowRule item, JSONArray jsonArray) {
        List<String> nodeList = new ArrayList<>(Math.max(4, jsonArray.size()));

        for (int i = 0; i < jsonArray.size(); i ++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            FlowRuleNode node = Pool.newInstance(FlowRuleNode.class);
            node.setFlowNo(item.getId());
            node.setAction(EnumUtil.getEnum(FlowAction.class, jsonObject.getString("action")));
            node.setWaitTime(jsonObject.getIntValue("waitTime"));
            node.setUnit(EnumUtil.getEnum(TimeUnit.class, jsonObject.getString("unit")));
            if (Objects.isEmpty(jsonObject.getString("target")) && item.getType() != 4) {
                jsonObject.put("target", "1");
            }
            node.setTarget(getTarget(jsonObject));
            List<String> departmentNos = new ArrayList<>();
            JSONArray departmentNosArray = jsonObject.getJSONArray("departmentNos");
            if (departmentNosArray != null) {
                departmentNosArray.forEach(id -> {
                    departmentNos.add((String) id);
                });
            }
            if (item.getType() != 4) {	// type=4为投诉报修超时配置规则
                if (Objects.isEmpty(jsonObject.getString("targetNo")) || departmentNos.size() == 0) {
                    return true;
                }
            }
            node.setDepartmentNos(departmentNos);
            node.setTargetNo(jsonObject.getString("targetNo"));
            node.setTargetName(jsonObject.getString("targetName"));
            node.setContent(jsonObject.getString("content"));
            if(Objects.nonNull(jsonObject.getBoolean("permissions"))) {
                node.setPermissions(jsonObject.getBoolean("permissions"));
            }

            jdbcSession.insert(node);
            nodeList.add(node.getId());
        }

        item.setNodeList(nodeList);
        return false;
    }

    private boolean updateNodes(FlowRule item, JSONArray jsonArray) {
        List<String> nodeList = new ArrayList<>(Math.max(4, jsonArray.size()));
        for (int i = 0; i < jsonArray.size(); i ++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            final String id = jsonObject.getString("id");

            FlowRuleNode node;
            if (Objects.isEmpty(id)) {
                node = Pool.newInstance(FlowRuleNode.class);
            } else {
                node = Pool.get(FlowRuleNode.class, id);
            }

            node.setFlowNo(item.getId());
            node.setAction(EnumUtil.getEnum(FlowAction.class, jsonObject.getString("action")));
            node.setWaitTime(jsonObject.getIntValue("waitTime"));
            node.setUnit(EnumUtil.getEnum(TimeUnit.class, jsonObject.getString("unit")));
            node.setTarget(getTarget(jsonObject));
            List<String> departmentNos = new ArrayList<>();
            JSONArray departmentNosArray = jsonObject.getJSONArray("departmentNos");
            if (departmentNosArray != null) {
                departmentNosArray.forEach(departmentNo -> {
                    departmentNos.add((String) departmentNo);
                });
            }
            if (item.getType() != 4) {	// type=4为投诉报修超时配置规则
                if (Objects.isEmpty(jsonObject.getString("targetNo")) || departmentNos.size() == 0) {
                    return true;
                }
            }
            node.setDepartmentNos(departmentNos);
            node.setTargetNo(jsonObject.getString("targetNo"));
            node.setTargetName(jsonObject.getString("targetName"));
            node.setContent(jsonObject.getString("content"));
            node.setPermissions(jsonObject.getBooleanValue("permissions"));

            if (Objects.isEmpty(id)) {
                jdbcSession.insert(node);
            } else {
                jdbcSession.updateById(node);
            }
            nodeList.add(node.getId());
        }

        deleteNodes(item, nodeList);
        item.setNodeList(nodeList);

        return false;
    }

    private void deleteNodes(FlowRule item, List<String> nodeList) {
        List<String> oldList = item.getNodeList();
        Iterator<String> it = oldList.iterator();
        while (it.hasNext()) {
            if (nodeList.contains(it.next())) {
                it.remove();
            }
        }

        for (String nodeNo : oldList) {
            jdbcSession.deleteById(FlowRuleNode.class, nodeNo);
        }
    }

    private Pair<List<String>, List<String>> toList(JSONObject json) {
        JSONArray keyList = json.getJSONArray("keyids");
        JSONArray wordList = json.getJSONArray("keyWords");

        List<String> keys = new ArrayList<>(keyList.size());
        List<String> words = new ArrayList<>(wordList.size());

        for (int i = 0; i < keyList.size(); i ++) {
            String key = keyList.getString(i);
            String word = wordList.getString(i);

            if (Objects.nonEmpty(key) && Objects.nonEmpty(word)) {
                keys.add(key);
                words.add(word);
            }
        }

        return new Pair<>(keys, words);
    }

    private Target getTarget(JSONObject json) {
        final String str = json.getString("target");
        if (Objects.isEmpty(str)) {
            return null;
        }

        Target target = EnumUtil.getEnum(Target.class, str);
        if (Objects.nonNull(target)) {
            return target;
        }

        try {
            JSONObject jsonObject = JSONObject.parseObject(str);
            return EnumUtil.getEnum(Target.class, jsonObject.getString("id"));
        } catch (Exception e) {
            return null;
        }

    }


}
